package com.cskaoyan.mall.search.service.impl;

import com.cskaoyan.mall.dto.ProductDto;
import com.cskaoyan.mall.search.converter.ProductConverter;
import com.cskaoyan.mall.search.dto.SearchRequest;
import com.cskaoyan.mall.search.dto.SearchResponse;
import com.cskaoyan.mall.search.entity.ItemDocument;
import com.cskaoyan.mall.search.repository.ProductRepository;
import com.cskaoyan.mall.search.service.ProductSearchService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Bowen Deng
 * @since 2022/07/16 13:51
 */
@Service
public class ProductSearchServiceImpl implements ProductSearchService {

    @Autowired
    ProductRepository productRepository;

    @Autowired
    ProductConverter productConverter;

    @Autowired
    ElasticsearchRestTemplate restTemplate;

    @Override
    public SearchResponse search(SearchRequest request) {

        SearchResponse searchResponse = new SearchResponse();
        // 该Builder包含所有搜索请求的参数
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        // 获取bool查询Builder
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 构造bool查询中match查询
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", request.getKeyword());
        // 将该查询加入bool查询must中
        boolQueryBuilder.must(matchQuery);



        // 构造bool查询中的范围查询
        if (!StringUtils.isEmpty(request.getPriceGt()) || !StringUtils.isEmpty(request.getPriceLte())){
        RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
        priceRange.gte(request.getPriceGt());
        priceRange.lt(request.getPriceLte());
        // 将范围查询添加到bool查询的filter中
        boolQueryBuilder.filter(priceRange);
        }

        // 将bool查询添加到NativeSearchQueryBuilder
        queryBuilder.withQuery(boolQueryBuilder);
        PageRequest price = null;
        // 构造分页参数
        if("1".equals(request.getSort())){
            price = PageRequest.of(request.getCurrentPage()-1, request.getPageSize(), Sort.by(Sort.Order.asc("price")));
        }else if("2".equals(request.getSort())){
            price = PageRequest.of(request.getCurrentPage()-1, request.getPageSize(), Sort.by(Sort.Order.desc("price")));
        }else{
            price = PageRequest.of(request.getCurrentPage()-1, request.getPageSize(),Sort.by(Sort.Order.asc("price")));
        }
        // 向NativeSearchQueryBuilder添加分页参数
        queryBuilder.withPageable(price);

        // 构造高亮参数
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font color='red'>").postTags("</font>");
        // 向NativeSearchQueryBuilder添加高亮参数
        queryBuilder.withHighlightBuilder(highlightBuilder);

        // 使用ElasticsearchRestTemplate发起搜索请求
        SearchHits<ItemDocument> search = restTemplate.search(queryBuilder.build(), ItemDocument.class);

        // 获取满足条件的总文档数量
        long totalHits = search.getTotalHits();
        searchResponse.setTotal(totalHits);

        // 获取包含所有命中文档的SearchHit对象
        List<SearchHit<ItemDocument>> searchHits = search.getSearchHits();

        ArrayList<ItemDocument> itemDocuments = new ArrayList<>();

        // 处理搜索到的结果集即SearchHit<ItemDocument>集合
        searchHits.forEach(hit -> {
            // 获取命中的文档
            ItemDocument content = hit.getContent();

            //获取高亮字段
            List<String> title = hit.getHighlightField("title");

            // 用高亮字段替换
            content.setTitle(title.get(0));

            itemDocuments.add(content);
        });

        List<ProductDto> productDtos = productConverter.items2Dto(itemDocuments);
        return searchResponse.ok(productDtos);
    }

    @Override
    public SearchResponse fuzzySearch(SearchRequest request) {
        List<ItemDocument> itemDocuments = productRepository.matchSearch(request.getKeyword());
        List<ProductDto> productDtos = productConverter.items2Dto(itemDocuments);
        SearchResponse searchResponse = new SearchResponse().ok(productDtos);
        return searchResponse;
    }
}
